package com.dxt;

import java.util.*;
import java.util.function.BinaryOperator;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class StreamDemo {

    public static void main(String[] args) {
//        test01();

//        test02();

//        test03();

//        test04();

//        test05();

        test06();

    }

    /**
     * 终结操作：
     * reduce(): 归并
     *   对流中的数据按照 自己指定的计算方式 计算出一个结果
     *   解释：可以传入一个初始值，它会按照指定的计算方式依次拿流中的元素与初始值进行计算，初始值进而会发生更新
     */
    public static void test06(){
        List<Author> authors = getAuthors();

        //1. 使用reduce求所有作者年龄的和
        Integer age_sum = authors.stream()
                .map(author -> author.getAge())
                .reduce(0, (result, element) -> result + element);
        System.out.println(age_sum);

        //2. 使用reduce求所有作者中年龄的最大值
        Integer max_age = authors.stream()
                .map(author -> author.getAge())
                .reduce(0, (result, element) -> result < element ? element : result);
        System.out.println(max_age);

        //3. 使用reduce求所有作者中年龄的最小值
        Integer min_age = authors.stream()
                .map(author -> author.getAge())
                .reduce(Integer.MAX_VALUE, (result, element) -> result < element ? result : element);
        System.out.println(min_age);
        //reduce() 不赋初值，默认使用流中第一个数据
        Optional<Integer> min_age_option = authors.stream()
                .map(author -> author.getAge())
                .reduce((result, element) -> result < element ? result : element);
        min_age_option.ifPresent(age -> System.out.println(age));


    }

    /**
     * 终结操作：查找与匹配
     * 1. anyMatch(): 用来判断是否 存在一个或多个 符合匹配条件的元素，结果为boolean类型
     * 2. allMatch(): 用来判断是否 所有元素 都满足匹配条件
     * 3. noneMatch(): 用来判断流中是否 所有元素 都不满足匹配条件
     * 4. findAny(): 查找流中任意一个满足条件的元素
     * 5. findFirst(): 查找流中第一个满足条件的元素
     */
    public static void test05(){
        List<Author> authors = getAuthors();

        //1. anyMatch()
        // 判断是否有年龄在29以上的玩家
        boolean b = authors.stream()
                .anyMatch(author -> author.getAge() > 29);
        System.out.println(b);

        //2. allMatch()
        boolean b1 = authors.stream()
                .distinct()
                .allMatch(author -> author.getAge() > 18);
        System.out.println(b1);

        //3. noneMatch()
        boolean b2 = authors.stream()
                .noneMatch(author -> author.getAge() > 100);
        System.out.println(b2); //true : 表示没有大于100岁的作者

        //4. findAny()
        Optional<Author> optionalAuthor = authors.stream()
                .filter(author -> author.getAge() > 2)
                .findAny();
        optionalAuthor.ifPresent(author -> System.out.println(author));

        //5. findFirst()
        Optional<Author> first = authors.stream()
                .sorted(((o1, o2) -> o1.getAge()- o2.getAge()))
                .findFirst();
        first.ifPresent(new Consumer<Author>() {
            @Override
            public void accept(Author author) {
                System.out.println(author);
            }
        });
    }

    /**
     * 终结操作
     * 1. forEach(): 对流中的元素进行遍历操作
     * 2. count(): 用来获取当前流中元素的个数
     * 3. min()&max(): 获取流中最小值 和 最大值，需要注意返回值类型
     * 4. collect(): 把当前流转换成一个集合(List,Set,Map)
     */
    public static void test04(){
        List<Author> authors = getAuthors();

        //1. forEach()
        authors.stream()
                .forEach(author -> System.out.println(author));

        //2. count()
        long num = authors.stream().count();
        System.out.println(num);

        //3. min() & max()
        //获取作者中最大的年龄
        Optional<Integer> max_age = authors.stream()
                .map(author -> author.getAge())
                .max((n1, n2) -> n1 - n2);
        System.out.println(max_age.get());
        //获取所有作者的所有书中最低分
        Optional<Integer> min_score = authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .map(book -> book.getScore())
                .min((s1, s2) -> s1 - s2);
        System.out.println(min_score.get());

        //4.collect()
        //4.1 获取一个存放所有作者名字的List集合
        List<String> author_list = authors.stream()
                .map(author -> author.getName())
                .collect(Collectors.toList());  //使用Collectors工具类中的方法
        System.out.println(author_list);
        //4.2 获取一个所有书名的Set集合
        Set<String> book_set = authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .map(book -> book.getName())
                .collect(Collectors.toSet());
        System.out.println(book_set);
        //4.3 获取一个map集合，map的key为作者名，val为List<Book>
        Map<String, List<Book>> map = authors.stream()
                .distinct()
                .collect(Collectors.toMap(author -> author.getName(), author -> author.getBooks()));
        System.out.println(map.get("易"));

    }

    /**
     * 中间操作
     * 1. filter(): 依据条件删除掉不满足条件的数据
     * 2. map(): 对流中的元素进行计算或者转换
     * 3. distinct(): 去除流中重复的元素，比较依赖的是equals()方法，如果是自定义对象，最好重写equals()方法
     * 4. sorted(): 对流中的元素进行排序
     * 5. limit(): 设置流的最大长度，超出的部分将被抛弃
     * 6. skip(): 跳过流中的前n个元素，返回剩下的元素
     * 7. flatMap(): 把一个对象转换成多个对象作为流中的元素
     */
    public static void test03(){
        List<Author> authors = getAuthors();

        // filter()
        authors.stream()
                .filter(author -> author.getName().length() > 2)    //保存满足条件的数据
                .forEach(author -> System.out.println(author));

        // map()
        authors.stream()
                .map(author -> author.getName())
                .forEach(name -> System.out.println(name));

        //distinct()
        authors.stream()
                .distinct()
                .forEach(author -> System.out.println(author));

        //sorted(): 对流中元素按照年龄降序排序
        authors.stream()
                .sorted(((o1, o2) -> o2.getAge() - o1.getAge()))
                .forEach(author -> System.out.println(author.getName() + " " + author.getAge()));

        //limit():
        //对流中元素按照年龄降序排序，要求不能有重复元素，输出其中年龄最大两个作家的姓名
        authors.stream()
                .distinct()
                .sorted(((o1, o2) -> o2.getAge()- o1.getAge()))
                .map(author -> author.getName())
                .limit(2)
                .forEach(name -> System.out.println(name));
        authors.stream()
                .distinct()
                .sorted(((o1, o2) -> o2.getAge()- o1.getAge()))
                .limit(2)
                .forEach(author -> System.out.println(author.getName()));

        //skip(): 跳过年龄最大的作者
        authors.stream()
                .distinct()
                .sorted(((o1, o2) -> o2.getAge() - o1.getAge()))
                .skip(1)
                .forEach(author -> System.out.println(author));

        //faltMap()
        //打印所有书籍的名字，对重复元素去重
        authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .distinct()
                .forEach(book -> System.out.println(book));
        //


    }


    /**
     * 创建/获取stream流的三种方式
     * 1. 对于单列集合（List, Set, Vector），有stream()方法，可以直接调用
     * 2. 对于数组，使用Arrays.stream(数组)或者Stream.of来获得stream流
     * 3. 对于双列集合（Map），转换成单列集合后再创建
     */
    public static void test02(){
        //1. 单列集合
        List<Integer> list = new LinkedList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        Stream<Integer> stream_list = list.stream();

        Set<Integer> set = new HashSet<>();
        set.add(1);
        set.add(2);
        set.add(3);
        Stream<Integer> stream_set = set.stream();

        //2. 数组
        Integer[] arr1 = {1,2,2,3,4,5};
        Stream<Integer> stream_arr1 = Arrays.stream(arr1);
        stream_arr1.distinct()
                .forEach(val -> System.out.println(val));

        Integer[] arr2 = {1,2,2,3,4,5};
        Stream<Integer> stream_arr2 = Stream.of(arr2);

        //3. 双列集合
        Map<String, Integer> map = new HashMap<>();
        map.put("迪迦", 1000);
        map.put("雷欧", 1200);
        map.put("艾斯", 900);
        Set<Map.Entry<String, Integer>> map_set = map.entrySet();   //转换
        Stream<Map.Entry<String, Integer>> stream_map = map_set.stream();
        stream_map.forEach(entry -> System.out.println(entry.getKey()));
    }

    /**
     * 第一个使用stream流的示例
     * 功能：对集合去重，获取集合中年龄小于18的作者信息
     */
    public static void test01(){
        List<Author> authors = getAuthors();
        authors.stream()
                .distinct()
                .filter(author -> author.getAge() < 18)
                .forEach(author -> System.out.println(author));
    }


    private static List<Author> getAuthors(){
        //数据初始化
        Author author1 = new Author(1L, "蒙多", 33, "一个从菜刀中明悟哲理的祖安人", null);
        Author author2 = new Author(2L, "亚拉索", 15, "狂风也追不上他的思想", null);
        Author author3 = new Author(3L, "易", 14, "是这个世界在限制他的思维", null);
        Author author4 = new Author(3L, "易", 14, "是这个世界在限制他的思维", null);

        //书籍列表
        List<Book> books1 = new ArrayList<Book>();
        List<Book> books2 = new ArrayList<Book>();
        List<Book> books3 = new ArrayList<Book>();

        books1.add(new Book(1L, "Java", "程序设计语言,计算机", 88, "java语言基础"));
        books1.add(new Book(2L, "c++", "底层程序设计语言,计算机", 80, "c++语言基础"));

        books2.add(new Book(3L, "go", "程序设计语言,高并发", 70, "go语言基础"));
        books2.add(new Book(3L, "go", "程序设计语言,高并发", 70, "go语言基础"));
        books2.add(new Book(4L, "分布式系统设计", "系统开发,应用", 80, "项目实战"));

        books3.add(new Book(5L, "redis", "缓存，中间件", 86, "技术应用"));
        books3.add(new Book(6L, "springboot", "框架", 90, "项目开发"));
        books3.add(new Book(6L, "springboot", "框架", 90, "项目开发"));

        author1.setBooks(books1);
        author2.setBooks(books2);
        author3.setBooks(books3);
        author4.setBooks(books3);

        List<Author> authors = new ArrayList<Author>(Arrays.asList(author1, author2, author3, author4));

        return authors;

    }
}
